Like a magician who appears to produce a bouquet of
flowers out of thin air, jQuery can create elements, attributes, and
text in a web page—as if by magic. But wait, there's more!
With jQuery, we can also make any of these things vanish. And, we can
take that bouquet of flowers and transform it into a<div class="magic" id="flowerstodove">dove</div>.
Manipulating attributes
The .addClass() and .removeClass()
methods to demonstrate how we can change the appearance of elements on a
page. Effectively, what these two methods are doing is manipulating the
class attribute (or, in DOM scripting parlance, the className property). The method creates or adds to the attribute, while .removeClass() deletes or shortens it. Add to these the .toggleClass() method, which alternates between adding and removing a class, and we have an efficient and robust way of handling classes. .addClass()
Nevertheless, the class attribute is only one of several attributes that we may need to access or change: for example, id and rel and href. For manipulating these attributes, jQuery provides the .attr() and .removeAttr() methods. We could even use .attr() and .removeAttr() to modify the class attribute, but the specialized and .removeClass()
methods are better in this case because they correctly handle cases
where multiple classes are applied to a single element, such as<div class="first second">. .addClass()
Non-class attributes
Some attributes are not so
easily manipulated without the help of jQuery. In addition, jQuery lets
us modify more than one attribute at a time, similar to the way we
worked with multiple CSS properties using the .css() method .
For example, we can easily set the id, rel, and title attributes for links, all at once. Let's start with some sample HTML:
<h1 id="f-title">Flatland: A Romance of Many Dimensions</h1>
<div id="f-author">by Edwin A. Abbott</div>
<h2>Part 1, Section 3</h2>
<h3 id="f-subtitle">
Concerning the Inhabitants of Flatland
</h3>
<div id="excerpt">an excerpt</div>
<div class="chapter">
<p class="square">Our Professional Men and Gentlemen are
Squares (to which class I myself belong) and Five-Sided
Figures or <a
href="http://en.wikipedia.org/wiki/Pentagon">Pentagons
</a>.
</p>
<p class="nobility hexagon">Next above these come the
Nobility, of whom there are several degrees, beginning at
Six-Sided Figures, or <a
href="http://en.wikipedia.org/wiki/Hexagon">Hexagons</a>,
and from thence rising in the number of their sides till
they receive the honourable title of <a
href="http://en.wikipedia.org/wiki/Polygon">Polygonal</a>,
or many-Sided. Finally when the number of the sides
becomes so numerous, and the sides themselves so small,
that the figure cannot be distinguished from a <a
href="http://en.wikipedia.org/wiki/Circle">circle</a>, he
is included in the Circular or Priestly order; and this is
the highest class of all.
</p>
<p><span class="pull-quote">It is a <span class="drop">Law
of Nature</span> with us that a male child shall have
<strong>one more side</strong> than his father</span>, so
that each generation shall rise (as a rule) one step in
the scale of development and nobility. Thus the son of a
Square is a Pentagon; the son of a Pentagon, a Hexagon;
and so on.
</p>
<!-- . . . code continues . . . -->
</div>
Now we can iterate through each of the links inside<div class="chapter">
and apply attributes to them one by one. If we only needed to set a
common attribute value for all of the links, we could do so with a
single line of code within our $(document).ready() handler:
$(document).ready(function() {
$('div.chapter a').attr({'rel': 'external'});
});
This technique works because we want the new rel
attribute to have the same value for each link. Often, though, the
attributes we add or change must have different values for each element.
One example of this is that for any given document, each id must be unique if we want our JavaScript code to behave predictably. To set a unique id for each link, we abandon the single-line solution in favor of jQuery's .each() method.
$(document).ready(function() {
$('div.chapter a').each(function(index) {
$(this).attr({
'rel': 'external',
'id': 'wikilink-' + index
});
});
});
The .each() method, which acts as an explicit iterator, is actually a more convenient form of the for
loop. It can be employed when the code we want to use on each item in
the selector's set of matched elements is too complex for the implicit iteration syntax. In our situation, the .each() method's anonymous function is passed an index that we can append to each id. This index argument acts as a counter, starting at 0 for the first link and incrementing by 1 with each successive link. Thus, setting the id to'wikilink-' + index gives the first link an id of wikilink-0, the second an id of wikilink-1, and so on.
We'll use the title
attribute to invite people to learn more about the linked term at
Wikipedia. In the HTML example, all of the links point to Wikipedia.
However, it's probably a good idea to make the selector expression a
little more specific, selecting only links that contain wikipedia in the href, just in case we decide to add a non-Wikipedia link to the HTML at a later time:
$(document).ready(function() {
$('div.chapter a[href*=wikipedia]').each(function(index) {
var $thisLink = $(this);
$thisLink.attr({
'rel': 'external',
'id': 'wikilink-' + index,
'title': 'learn more about ' + $thisLink.text() +
' at Wikipedia'
});
});
});
One thing worth noting here is that we're now storing $(this) in a variable called $thisLink, simply because we end up using it more than once.
With all three attributes set, the HTML of the first link, for example, now looks like this:
<a href="http://en.wikipedia.org/wiki/Pentagon" rel="external"
id="wikilink-0" title="learn more about Pentagons at
Wikipedia">Pentagons</a>
The $() factory function revisited
We've been using the $()
function to access elements in a document. In a sense, this function
lies at the very heart of the jQuery library, as it is used every time
we attach an effect, event, or property to a matched set of elements.
What's more, the $()
function has yet another trick within its parentheses—a
feature so powerful that it can change not only the visual appearance
but also the actual contents of a page. Simply by inserting a snippet of
HTML code inside the parentheses, we can create an entirely new DOM
structure from thin air.
Accessibility reminder
We should keep in mind,
once again, the inherent danger in making certain functionality, visual
appeal, or textual information available only to those with web
browsers capable of (and enabled for) using JavaScript. Important
information should be accessible to all, not just people who happen to
be using the right software.
A feature commonly seen on FAQ pages is the back to top
link that appears after each question-and-answer pair. It could be
argued that these links serve no semantic purpose and therefore can be
included via JavaScript legitimately as an enhancement for a subset of
the visitors to a page. For our example, we'll add a back to top link after each paragraph, as well as the anchor to which the back to top links will take us. To begin, we simply create the new elements:
$(document).ready(function() {
$('<a href="#top">back to top</a>');
$('<a id="top"></a>');
});
Here is what the page looks like at this point:
But where are the back to top
links and the anchor? Shouldn't they appear on the page? The answer is
no. While the two lines do create the elements, they don't yet add the
elements to the page. To do that, we can use one of the many jQuery insertion methods.